#include "jtokyotyrant_jni_RDBQRYJni.h"
#include "myconf.h"

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBQRYJni_init
  (JNIEnv *env, jclass cls) {
  init_native_qry_field(env, cls);
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    initialize
 * Signature: (Ljtokyotyrant/jni/RDBTBLJni;)V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBQRYJni_initialize
  (JNIEnv *env, jobject self, jobject jrdb) {
  RDBQRY *qry = tcrdbqrynew(native_rdb(env, jrdb));
  set_native_qry(env, self, qry);
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    destruct
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBQRYJni_destruct
  (JNIEnv *env, jobject self) {
	RDBQRY *qry = native_qry(env, self);
	if (qry) tcrdbqrydel(qry);
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    addcond
 * Signature: (Ljava/lang/String;ILjava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBQRYJni_addcond
  (JNIEnv *env, jobject self, jstring jname, jint jop, jstring jexpr) {
	if (!jname || !jexpr) {
		throwillarg(env, "jname or jexpr is null");
		return;
	}
	
	jboolean ic_name;
	const char *name = (*env)->GetStringUTFChars(env, jname, &ic_name);
	if (!name) {
		throwoutmem(env, "jname to char*");
		return;
	}

	jboolean ic_expr;
	const char *expr = (*env)->GetStringUTFChars(env, jexpr, &ic_expr);
	if (!expr) {
		throwoutmem(env, "jexpr to char*");
		return;
	}
	
	tcrdbqryaddcond(native_qry(env, self), name, jop, expr);
	
	if (ic_name) (*env)->ReleaseStringUTFChars(env, jname, name);
	if (ic_expr) (*env)->ReleaseStringUTFChars(env, jexpr, expr);
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    setorder
 * Signature: (Ljava/lang/String;I)V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBQRYJni_setorder
  (JNIEnv *env, jobject self, jstring jname, jint jtype) {
	if (!jname) {
		throwillarg(env, "jname is null");
		return;
	}

	jboolean ic_name;
	const char *name = (*env)->GetStringUTFChars(env, jname, &ic_name);
	if (!name) {
		throwoutmem(env, "jname to char*");
		return;
	}

	tcrdbqrysetorder(native_qry(env, self), name, jtype);

	if (ic_name) (*env)->ReleaseStringUTFChars(env, jname, name);
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    setlimit
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_jtokyotyrant_jni_RDBQRYJni_setlimit
  (JNIEnv *env, jobject self, jint jmax, jint jskip) {
	tcrdbqrysetlimit(native_qry(env, self), jmax, jskip);
}


/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    search
 * Signature: ()Ljava/util/List;
 */
JNIEXPORT jobject /*List<byte>*/ JNICALL Java_jtokyotyrant_jni_RDBQRYJni_search
  (JNIEnv *env, jobject self) {
  	TCLIST *list = tcrdbqrysearch(native_qry(env, self));
  	if (!list) {
  		throwoutmem(env, "tcrdbqrysearch fail");
  		return NULL;
  	}
  	
  	jobject jlist = tclist2jbytelist(env, list);
  	
  	tclistdel(list);
	return jlist;
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    searchout
 * Signature: ()Z
 */
JNIEXPORT jboolean JNICALL Java_jtokyotyrant_jni_RDBQRYJni_searchout
  (JNIEnv *env, jobject self) {
  return tcrdbqrysearchout(native_qry(env, self));
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    searchget
 * Signature: ()Ljava/util/List;
 */
JNIEXPORT jobject /*List<Map<String, byte[]>>*/ JNICALL Java_jtokyotyrant_jni_RDBQRYJni_searchget
  (JNIEnv *env, jobject self) {
	TCLIST *list = tcrdbqrysearchget(native_qry(env, self));
  	if (!list) {
  		throwoutmem(env, "tcrdbqrysearchget fail");
  		return NULL;
  	}

	int num = tclistnum(list);
	
	jobject jlist = new_jobject(env, "java/util/ArrayList", "(I)V", num);
	
	for (int i = 0; i < num; i++) {
		TCMAP *cols = tcrdbqryrescols(list, i);
		if (!cols) {
			throwoutmem(env, "tcrdbqryrescols fail");
			return NULL;
		}
		
		jobject jcols = tcmap2jmap(cols, env, JTTMAPTYPESTRG, JTTMAPTYPEBYTS);
		if (!jcols) {
			throwillsta(env, "tcmap2jmap fail");
			return NULL;
		}
		
		invoke_jboolean_method(env, jlist, "add", "(Ljava/lang/Object;)Z", jcols);
		
		tcmapdel(cols);
	}
  	
  	tclistdel(list);
	return jlist;
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    searchcount
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_jtokyotyrant_jni_RDBQRYJni_searchcount
  (JNIEnv *env, jobject self) {
	return tcrdbqrysearchcount(native_qry(env, self));
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    hint
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_jtokyotyrant_jni_RDBQRYJni_hint
  (JNIEnv *env, jobject self) {
	const char *hint = tcrdbqryhint(native_qry(env, self));
	jstring jhint = (*env)->NewStringUTF(env, hint);
	if (!jhint) {
		throwoutmem(env, "jstring allocate error");
		return NULL;
	}
	return jhint;
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    metasearch
 * Signature: ([Ljtokyotyrant/RDBQRY;I)Ljava/util/List;
 */
JNIEXPORT jobject JNICALL Java_jtokyotyrant_jni_RDBQRYJni_metasearch
  (JNIEnv *env, jobject self, jobjectArray jqrys, jint jtype) {
	if (!jqrys) {
		throwillarg(env, "jqrys is null");
		return NULL;
	}
	
	int qrynum = (*env)->GetArrayLength(env, jqrys);
	RDBQRY **qrys = tcmalloc(sizeof(RDBQRY) * qrynum);
	if (!qrys) {
		throwoutmem(env, "tcmalloc out of memory");
		return NULL;
	}
	
	RDBQRY **tmpqrys = qrys;
	for (int i = 0; i < qrynum; i++) {
		jobject jqry = (*env)->GetObjectArrayElement(env, jqrys, i);
		*tmpqrys++ = native_qry(env, jqry);
	}

	TCLIST *list = tcrdbmetasearch(qrys, qrynum, jtype);
	tcfree(qrys);

	jobject jlist = tclist2jbytelist(env, list);
	
	tclistdel(list);
	
	return jlist;
}

/*
 * Class:     jtokyotyrant_jni_RDBQRYJni
 * Method:    parasearch
 * Signature: ([Ljtokyotyrant/RDBQRY;)Ljava/util/List;
 */
JNIEXPORT jobject /*List<Map<String, byte[]>>*/ JNICALL Java_jtokyotyrant_jni_RDBQRYJni_parasearch
  (JNIEnv *env, jobject self, jobjectArray jqrys) {
	if (!jqrys) {
		throwillarg(env, "jqry is null");
		return NULL;
	}
	
	int qrynum = (*env)->GetArrayLength(env, jqrys);
	RDBQRY **qrys = tcmalloc(sizeof(RDBQRY) * qrynum);
	if (!qrys) {
		throwoutmem(env, "tcmalloc out of memory");
		return NULL;
	}
	
	RDBQRY **tmpqrys = qrys;
	for (int i = 0; i < qrynum; i++) {
		jobject jqry = (*env)->GetObjectArrayElement(env, jqrys, i);
		*tmpqrys++ = native_qry(env, jqry);
	}
	
	TCLIST *list = tcrdbparasearch(qrys, qrynum);
	tcfree(qrys);

	int num = tclistnum(list);
	
	jobject jlist = new_jobject(env, "java/util/ArrayList", "(I)V", num);
	
	for (int i = 0; i < num; i++) {
		TCMAP *cols = tcrdbqryrescols(list, i);
		if (!cols) {
			throwoutmem(env, "tcrdbqryrescols fail");
			return NULL;
		}
		
		jobject jcols = tcmap2jmap(cols, env, JTTMAPTYPESTRG, JTTMAPTYPEBYTS);
		if (!jcols) {
			throwillsta(env, "tcmap2jmap fail");
			return NULL;
		}
		
		invoke_jboolean_method(env, jlist, "add", "(Ljava/lang/Object;)Z", jcols);
		
		tcmapdel(cols);
	}
  	
  	tclistdel(list);
	return jlist;
}

